using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;

namespace WPFTemplateLib.Models
{
	/// <summary>
	/// 可勾选的树节点类
	/// </summary>
	public class CheckableTreeNode : CheckableItem
	{
		#region 成员、构造

		/// <inheritdoc />
		public CheckableTreeNode(string tag) : base(tag)
		{
			Init();
		}

		/// <inheritdoc />
		public CheckableTreeNode(string tag, string showName) : base(tag, showName)
		{
			Init();
		}

		/// <inheritdoc />
		public CheckableTreeNode(string tag, string showName, string groupName) : base(tag, showName, groupName)
		{
			Init();
		}

		/// <summary>
		/// 初始化方法
		/// </summary>
		private void Init()
		{
			InitChildrenEvent();
		}

		#endregion

		#region 属性

		/// <summary>
		/// 父节点
		/// </summary>
		public CheckableTreeNode Parent { get; set; }

		/// <summary>
		/// 子节点集合（添加子节点时会自动设置父节点）
		/// </summary>
		public ObservableCollection<CheckableTreeNode> Children { get; set; } = new();

		/// <summary>
		/// 是否有子节点
		/// </summary>
		public bool HasChildren => Children.Count > 0;

		/// <summary>
		/// 层级
		/// </summary>
		public int Level { get; set; }

		#endregion

		#region 方法

		/// <inheritdoc />
		protected override void PropertyChangedHandle(object sender, PropertyChangedEventArgs e)
		{
			base.PropertyChangedHandle(sender, e);
			switch(e.PropertyName)
			{
				case nameof(IsChecked):
				{
					if(HasChildren)
					{
						ChangeAllNodesCheckStatus(this, IsChecked);
					}
					break;
				}
				case nameof(Children):
				{
					if(Children != null)
					{
						foreach(CheckableTreeNode child in Children)
						{
							child.Parent = this;
						}

						InitChildrenEvent();
					}
					break;
				}
				case nameof(Level):
				{
					RefreshChildrenLevel();
					break;
				}
				case nameof(Parent):
				{
					if(Parent != null)
					{
						Level = Parent.Level + 1;
					}
					break;
				}
			}
		}

		/// <summary>
		/// 初始化子节点集合事件
		/// </summary>
		private void InitChildrenEvent()
		{
			Children.CollectionChanged -= Children_CollectionChanged;
			Children.CollectionChanged += Children_CollectionChanged;
		}

		/// <summary>
		/// 子节点集合变更事件
		/// </summary>
		private void Children_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			if(e.NewItems != null)
			{
				foreach(var newItem in e.NewItems)
				{
					var item = newItem as CheckableTreeNode;
					if(item == null)
						continue;

					item.Parent = this;
				}
			}

			if(e.OldItems != null)
			{
				foreach(var oldItem in e.OldItems)
				{
					var item = oldItem as CheckableTreeNode;
					if(item == null)
						continue;

					item.Parent = null;
				}
			}

			OnPropertyChanged(nameof(HasChildren));
		}

		/// <summary>
		/// 刷新子节点 Level
		/// </summary>
		public void RefreshChildrenLevel()
		{
			foreach(var child in Children)
			{
				child.Level = Level + 1;
				child.RefreshChildrenLevel();
			}
		}

		/// <summary>
		/// 取消勾选下属所有节点
		/// </summary>
		public void UncheckAllNodes()
		{
			ChangeAllNodesCheckStatus(this, false);
		}

		/// <summary>
		/// 勾选下属所有节点
		/// </summary>
		public void CheckAllNodes()
		{
			ChangeAllNodesCheckStatus(this, true);
		}

		/// <summary>
		/// 更改指定节点及其下属所有节点的勾选状态
		/// </summary>
		public static void ChangeAllNodesCheckStatus(CheckableTreeNode node, bool isChecked)
		{
			node.IsChecked = isChecked;

			foreach(var childNode in node.Children)
			{
				ChangeAllNodesCheckStatus(childNode, isChecked);
			}
		}

		/// <summary>
		/// 获取所有叶子节点
		/// </summary>
		/// <param name="levelLimitHigherOrEqual">层级限制（大等于指定层级才算叶子节点）</param>
		/// <param name="isOnlyChecked">是否只选取勾选的</param>
		/// <returns></returns>
		public List<CheckableTreeNode> GetLeafs(int? levelLimitHigherOrEqual = null, bool isOnlyChecked = false)
		{
			var list = new List<CheckableTreeNode>();
			foreach(var child in Children)
			{
				if(!child.HasChildren)
				{
					if(levelLimitHigherOrEqual == null || child.Level >= levelLimitHigherOrEqual)
					{
						list.Add(child);
					}
				}
				else
				{
					var childrenLeafs = child.GetLeafs(levelLimitHigherOrEqual, isOnlyChecked);
					list.AddRange(childrenLeafs);
				}
			}

			if(isOnlyChecked)
			{
				list = list.Where(x => x.IsChecked).ToList();
			}

			return list;
		}

		/// <summary>
		/// 获取所有选中的叶子节点
		/// </summary>
		/// <param name="levelLimitHigherOrEqual">层级限制（大等于指定层级才算叶子节点）</param>
		/// <returns></returns>
		public List<CheckableTreeNode> GetCheckedLeafs(int? levelLimitHigherOrEqual = null)
		{
			return GetLeafs(levelLimitHigherOrEqual, true);
		}

		/// <summary>
		/// 获取所有勾选的叶子节点的名称列表
		/// </summary>
		/// <param name="levelLimitHigherOrEqual">层级限制（大等于指定层级才算叶子节点）</param>
		/// <returns></returns>
		public List<string> GetCheckedLeafsNameList(int? levelLimitHigherOrEqual = null)
		{
			var leafs = GetCheckedLeafs(levelLimitHigherOrEqual);
			var list = leafs.Select(x => x.ShowName).ToList();
			return list;
		}

		/// <summary>
		/// 获取所有勾选的叶子节点的Tag列表
		/// </summary>
		/// <param name="levelLimitHigherOrEqual">层级限制（大等于指定层级才算叶子节点）</param>
		/// <returns></returns>
		public List<string> GetCheckedLeafsTagList(int? levelLimitHigherOrEqual = null)
		{
			var leafs = GetCheckedLeafs(levelLimitHigherOrEqual);
			var list = leafs.Select(x => x.Tag).ToList();
			return list;
		}

		#endregion
	}

	/// <summary>
	/// 可勾选的树节点类（泛型版）
	/// </summary>
	/// <typeparam name="T"><see cref="CheckableItem"/> 类或其子类</typeparam>
	public class CheckableTreeNode<T> : BaseTreeNode
	where T : CheckableItem
	{
		#region 成员、构造

		public CheckableTreeNode(T checkableItem)
		{
			CheckableItem = checkableItem;
			if(CheckableItem == null)
			{
				throw new ArgumentNullException(nameof(checkableItem));
			}
			else
			{
				CheckableItem.CheckStatusChanged -= CheckableItem_CheckStatusChanged;
				CheckableItem.CheckStatusChanged += CheckableItem_CheckStatusChanged;
			}
		}

		#endregion

		#region 属性

		/// <summary>
		/// 可勾选项
		/// </summary>
		public T CheckableItem { get; private set; }

		#endregion

		#region 方法

		/// <summary>
		/// 可勾选项勾选状态变更
		/// </summary>
		/// <param name="obj"></param>
		private void CheckableItem_CheckStatusChanged(CheckableItem obj)
		{
			if(HasChildren)
			{
				ChangeAllNodesCheckStatus(this, CheckableItem.IsChecked);
			}
		}

		/// <summary>
		/// 取消勾选下属所有节点
		/// </summary>
		public void UncheckAllNodes()
		{
			ChangeAllNodesCheckStatus(this, false);
		}

		/// <summary>
		/// 勾选下属所有节点
		/// </summary>
		public void CheckAllNodes()
		{
			ChangeAllNodesCheckStatus(this, true);
		}

		/// <summary>
		/// 更改指定节点及其下属所有节点的勾选状态
		/// </summary>
		public static void ChangeAllNodesCheckStatus(CheckableTreeNode<T> node, bool isChecked)
		{
			node.CheckableItem.IsChecked = isChecked;

			foreach(var childNode in node.Children)
			{
				ChangeAllNodesCheckStatus(childNode as CheckableTreeNode<T>, isChecked);
			}
		}

		/// <summary>
		/// 获取所有叶子节点
		/// </summary>
		/// <param name="levelLimitHigherOrEqual">层级限制（大等于指定层级才算叶子节点）</param>
		/// <param name="isOnlyChecked">是否只选取勾选的</param>
		/// <returns></returns>
		public List<CheckableTreeNode<T>> GetLeafs(int? levelLimitHigherOrEqual = null, bool isOnlyChecked = false)
		{
			var list = base.GetLeafs(levelLimitHigherOrEqual).Cast<CheckableTreeNode<T>>().ToList();

			if(isOnlyChecked)
			{
				list = list.Where(x => x.CheckableItem.IsChecked).ToList();
			}

			return list;
		}

		/// <summary>
		/// 获取所有选中的叶子节点
		/// </summary>
		/// <param name="levelLimitHigherOrEqual">层级限制（大等于指定层级才算叶子节点）</param>
		/// <returns></returns>
		public List<CheckableTreeNode<T>> GetCheckedLeafs(int? levelLimitHigherOrEqual = null)
		{
			return GetLeafs(levelLimitHigherOrEqual, true);
		}

		/// <summary>
		/// 获取所有勾选的叶子节点的名称列表
		/// </summary>
		/// <param name="levelLimitHigherOrEqual">层级限制（大等于指定层级才算叶子节点）</param>
		/// <returns></returns>
		public List<string> GetCheckedLeafsNameList(int? levelLimitHigherOrEqual = null)
		{
			var leafs = GetCheckedLeafs(levelLimitHigherOrEqual);
			var list = leafs.Select(x => x.CheckableItem.ShowName).ToList();
			return list;
		}

		/// <summary>
		/// 获取所有勾选的叶子节点的Tag列表
		/// </summary>
		/// <param name="levelLimitHigherOrEqual">层级限制（大等于指定层级才算叶子节点）</param>
		/// <returns></returns>
		public List<string> GetCheckedLeafsTagList(int? levelLimitHigherOrEqual = null)
		{
			var leafs = GetCheckedLeafs(levelLimitHigherOrEqual);
			var list = leafs.Select(x => x.CheckableItem.Tag).ToList();
			return list;
		}

		#endregion
	}
}
